/**
 * @file ASpect.h
 * @author your name (you@domain.com)
 * @brief 为了实现切面的充分解耦合，我们的切面不必通过继承方式实现，而且也不必要求切面必须具备Before 和 After 方法，只要具备任意一个方法即可，给使用者提供最大的便利性和灵活性。
 *  实现这个功能有点复杂，复杂的方式在于切面可能具有某个方法也可能不具有某个方法，具有就调用，不具有也不会出错。
 *  我们需要在编译器检测类型是否有某种方法。——使用元编程的方式。
 * @version 0.1
 * @date 2021-07-07
 * 
 * @copyright Copyright (c) 2021
 * 
 */
#pragma once

#include <utility>
#include <type_traits>

/**
 * @brief 这个 has_member_foo 的作用就是检查类型是否存在非静态成员函数foo，具体的实现思路是这样的：定义一个Check函数，有两种重载形式，利用C++ 的SIFNA（Substitution failure is not an erro--替换失败不算错）特性，
 * 由于模板实例化的过程中会优先选择匹配度最高的重载函数，在模板实例化的过程中检测类型是否存在 foo 函数，如果存在则返回 `std::true_type`，否则返回 `std::false_type`。
 * 最后检测Check 函数的返回类型即可直到类型是否存在foo 函数。需要注意这里用到了C++ 11 的 auto + decltype 实现的返回类型后置特性，用这个特性的主要目的是我们无法直接得到 Check 的返回类型
 * 我们需要借助模板参数 T 才能得到 Check 的返回类型
 * 
 * @tparam T 
 */
template <typename T, typename... Args>
struct has_member_foo
{
private:
    template <typename U>
    static auto Check(int) -> decltype(std::declval<U>().foo(std::declval<Args>()...), std::true_type());

    template <typename U>
    static std::false_type Check(...);

public:
    enum
    {
        value = std::is_same<decltype(Check<T>(0)), std::true_type>::value
    };
};

// `##` 就是宏 替代

using namespace std;
#define HAS_MEMBER(member)                                                                                       \
    template <typename T, typename... Args>                                                                      \
    struct has_member_##member                                                                                   \
    {                                                                                                            \
    private:                                                                                                     \
        template <typename U>                                                                                    \
        static auto Check(int) -> decltype(std::declval<U>().member(std::declval<Args>()...), std::true_type()); \
        template <typename U>                                                                                    \
        static std::false_type Check(...);                                                                       \
                                                                                                                 \
    public:                                                                                                      \
        enum                                                                                                     \
        {                                                                                                        \
            value = std::is_same<decltype(Check<T>(0)), std::true_type>::value                                   \
        };                                                                                                       \
    };

HAS_MEMBER(Before)
HAS_MEMBER(After)

#include "NoCopy.h"

template <typename Func, typename... Args>
struct Aspect : NonCopyable //支持模板 多种类型的支持
{
    Aspect(Func &&f) : m_func(std::forward<Func>(f))
    {
    }

    template <typename Head, typename... Tail>
    void Invoke(Args &&...args, Head &&headAspect, Tail &&...tailAspect)
    {
        headAspect.Before(std::forward<Args>(args)...);
        Invoke(std::forward<Args>(args)..., std::forward<Tail>(tailAspect)...);
        headAspect.After(std::forward<Args>(args)...);
    }

    template <typename T>
    typename std::enable_if<has_member_Before<T, Args...>::value && has_member_After<T, Args...>::value>::type Invoke(Args &&...args, T &&aspect)
    {
        aspect.Before(std::forward<Args>(args)...); //核心逻辑之前的切面逻辑
        m_func(std::forward<Args>(args)...);        //核心逻辑
        aspect.After(std::forward<Args>(args)...);  //核心逻辑之后的切面逻辑
    }

    template <typename T>
    typename std::enable_if<has_member_Before<T, Args...>::value && !has_member_After<T, Args...>::value>::type Invoke(Args &&...args, T &&aspect)
    {
        aspect.Before(std::forward<Args>(args)...); //核心逻辑之前的切面逻辑
        m_func(std::forward<Args>(args)...);        //核心逻辑
    }

    template <typename T>
    typename std::enable_if<!has_member_Before<T, Args...>::value && has_member_After<T, Args...>::value>::type Invoke(Args &&...args, T &&aspect)
    {
        m_func(std::forward<Args>(args)...);       //核心逻辑
        aspect.After(std::forward<Args>(args)...); //核心逻辑之后的切面逻辑
    }

private:
    Func m_func; //被织入的函数
};
template <typename T>
using identity_t = T;

//AOP的辅助函数，简化调用
template <typename... AP, typename... Args, typename Func>
void Invoke(Func &&f, Args &&...args)
{
    Aspect<Func, Args...> asp(std::forward<Func>(f));
    asp.Invoke(std::forward<Args>(args)..., identity_t<AP>()...);
}

